﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Oracle.DataAccess.Client;

namespace GestionCegep.Objects
{
    public class Cours : PersistentObject
    {
        private static Cours oldCours = new Cours(string.Empty);

        // Différentes requetes a la base de donnees pour la gestion des cours
        private const string selectQuery = "SELECT SIGLE, NOM, CREDIT, ENSEIGNANT, ID_DEPARTEMENT FROM COURS";
        private const string lockQuery = "LOCK TABLE COURS IN EXCLUSIVE MODE";
        private const string insertQuery = "INSERT INTO COURS(SIGLE) VALUES('{0}')";
        private const string updateQuery = "UPDATE COURS SET NOM = '{1}', CREDIT = {2}, ENSEIGNANT = {3}, ID_DEPARTEMENT = {4} WHERE SIGLE = '{0}'";
        private const string deleteQuery = "DELETE FROM COURS WHERE SIGLE = '{0}'";

        private string sigle;                      // Sigle du cours
        private string nom;                        // Titre du cours
        private int credit;                        // Nombre de credit du cours
        private Enseignant enseignant;             // Enseignant du cours
        private Departement departement;           // Departement du cours

        // Constructeur
        private Cours(string sigle, string nom, int credit, Enseignant enseignant, Departement departement, bool isNew = false)
        {
            this.sigle = sigle;
            this.nom = nom;
            this.credit = credit;
            this.enseignant = enseignant;
            this.departement = departement;
            this.isNew = isNew;
        }

        public Cours(string sigle)
        {
            this.sigle = sigle;
            isNew = true;
        }

        public Cours(string sigle, string nom, int credit, Enseignant enseignant, Departement departement)
        {
            this.sigle = sigle;
            this.nom = nom;
            this.credit = credit;
            this.enseignant = enseignant;
            this.departement = departement;
            this.isNew = true;
        }

        public string Sigle { get { return sigle; } set { sigle = value; } }
        public string Nom { get { return nom; } set { nom = value; } }
        public int Credit { get { return credit; } set { credit = value; } }
        public Enseignant Enseignant { get { return enseignant; } set { enseignant = value; } }
        public Departement Departement { get { return departement; } set { departement = value; } }

        // Insertion d'un cours dans la base de données
        public override void InsertIntoDataBase(OracleConnection OracleConnection, DataStore dataStore)
        {
            OracleCommand command;    // Commande Oracle
            string departementId = departement != null ? departement.Id.ToString() : string.Empty;
            string enseignantNumero = enseignant != null ? enseignant.NumeroEmploye.ToString() : string.Empty;
            try
            {
                command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = lockQuery; // On verouille la table (Concurrence)
                command.ExecuteNonQuery(); // Execution de la commande
                
                // Journalisation des modifications
                command.CommandText = String.Format(insertQuery, sigle, nom, credit, enseignantNumero, departementId);
                command.ExecuteNonQuery();

                dataStore.CurrentTransaction.PushLogToBD(LogActions.Defaire, String.Format(deleteQuery, sigle));
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Refaire, String.Format(insertQuery, sigle));

                dataStore.CurrentTransaction.Commit(); // Confirmation de la transaction
                dataStore.LesCours.Add(this);  // Ajout du cours a la liste des cours (Pour le DataGridView)
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Vérouillage pour la mise a jour (Concurrence)
        public override void LockForUpdate(OracleConnection OracleConnection)
        {
            try
            {
                OracleCommand command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = selectQuery + " WHERE SIGLE = '" + sigle + "' FOR UPDATE"; // Vérouillage pour la mise a jour (Concurrence)
                command.ExecuteScalar();

                oldCours.sigle = sigle;
                oldCours.nom = nom;
                oldCours.credit = credit;
                oldCours.departement = departement;
                oldCours.enseignant = enseignant;
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Mise a jour de la table cours
        public override void UpdateIntoDataBase(MyOracleTransaction currentTransaction)
        {
            string enseignantNumero = enseignant != null ? enseignant.NumeroEmploye.ToString() : "NULL";
            string departementId = departement != null ? departement.Id.ToString() : "NULL";
            try
            {
                OracleCommand command = currentTransaction.Connection.CreateCommand(); // Creation de la commande
                command.CommandText = String.Format(updateQuery, sigle, nom, credit.ToString(), enseignantNumero, departementId); // Mise a jour dans la table
                command.ExecuteNonQuery();

                // Journalisation des modifications
                enseignantNumero = oldCours.enseignant != null ? oldCours.enseignant.NumeroEmploye.ToString() : "NULL";
                departementId = oldCours.departement != null ? oldCours.departement.Id.ToString() : "NULL";

                currentTransaction.PushLogToBD(LogActions.Defaire, String.Format(updateQuery, oldCours.sigle, oldCours.nom, oldCours.credit.ToString(), enseignantNumero, departementId));
                currentTransaction.PushLogToBD(LogActions.Refaire, command.CommandText);

                currentTransaction.Commit(); // Confirmation de la transaction
            }
            catch (OracleException exception)
            {
                nom = oldCours.nom;
                credit = oldCours.credit;
                enseignant = oldCours.enseignant;
                departement = oldCours.departement;
                throw exception;
            }
        }

        // Suppression d'un cours
        public override void DeleteFromDataBase(OracleConnection OracleConnection, DataStore dataStore)
        {
            string enseignantNumero = enseignant != null ? enseignant.NumeroEmploye.ToString() : "NULL";
            string departementId = departement != null ? departement.Id.ToString() : "NULL";
            OracleCommand command; // Commande Oracle
            try
            {
                command = OracleConnection.CreateCommand(); // Creation de la nouvelle commande Oracle
                command.CommandText = lockQuery; // Vérouillage la table (Concurrence)
                command.ExecuteNonQuery();

                // Journalisation
                command.CommandText = String.Format(deleteQuery, sigle);
                command.ExecuteNonQuery();
                
                string insertQuery = "INSERT INTO COURS VALUES('{0}','{1}',{2},{3},{4})"; // Insert pour la journalisation (Contraire de delete)
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Defaire, String.Format(insertQuery, sigle, nom, credit, enseignantNumero, departementId));
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Refaire, command.CommandText);

                dataStore.CurrentTransaction.Commit(); // Confirmation de la transaction
                dataStore.LesCours.Remove(this); // On retire le cours de la liste des cours pour le DataGridView
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Balayage de la table copurs pour obtenir toutes les informations
        public static List<Cours> GetCoursFromDataBase(OracleConnection OracleConnection, List<Enseignant> enseignants, List<Departement> departements)
        {
            List<Cours> lesCours = new List<Cours>(); // Liste des cours

            try
            {
                string enseignantNumero;
                string departementId;
                string creditString;
                Enseignant enseignant;
                Departement departement;
                int credit;
                OracleCommand command = OracleConnection.CreateCommand(); // Creation de la commande Oracle
                command.CommandText = selectQuery;
                OracleConnection.Open();
                OracleDataReader reader = command.ExecuteReader(); // Execution de la requete select

                // Tant qu'il y a des donnees dans la table Cours
                while (reader.Read())
                {
                    enseignantNumero = reader["ENSEIGNANT"].ToString();
                    departementId = reader["ID_DEPARTEMENT"].ToString();
                    creditString = reader["CREDIT"].ToString();

                    if (!string.IsNullOrEmpty(enseignantNumero))
                        enseignant = enseignants.First(e => enseignantNumero.Equals(e.NumeroEmploye.ToString()));
                    else
                        enseignant = null;
                    if (!String.IsNullOrEmpty(departementId))
                        departement = departements.First(d => departementId.Equals(d.Id.ToString()));
                    else
                        departement = null;
                    if (!String.IsNullOrEmpty(creditString))
                        credit = Convert.ToInt32(creditString);
                    else
                        credit = 0;
                    Cours cours = new Cours(reader["SIGLE"].ToString(),
                                            reader["NOM"].ToString(),
                                            credit,
                                            enseignant,
                                            departement,
                                            false);
                    lesCours.Add(cours); // Ajout de tout les cours a la liste des cours
                }
                OracleConnection.Close();
            }
            catch (Exception exception)
            {
                throw exception;
            }

            return lesCours; // On retourne les cours pour le remplissable du DataGridView
        }

    }
}
